/*
 * Copyright (c) 2010-2025 Belledonne Communications SARL.
 *
 * This file is part of Liblinphone
 * (see https://gitlab.linphone.org/BC/public/liblinphone).
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#include <list>

#include "auth-info/auth-info.h"
#include "c-wrapper/c-wrapper.h"
#include "linphone/api/c-auth-info.h"
#include "linphone/lpconfig.h"
#include "private_functions.h"

using namespace LinphonePrivate;

LinphoneAuthInfo *linphone_auth_info_new(const char *username,
                                         const char *userid,
                                         const char *passwd,
                                         const char *ha1,
                                         const char *realm,
                                         const char *domain) {
	return AuthInfo::createCObject(username ? username : "", userid ? userid : "", passwd ? passwd : "", ha1 ? ha1 : "",
	                               realm ? realm : "", domain ? domain : "");
}

LinphoneAuthInfo *linphone_auth_info_new_for_algorithm(const char *username,
                                                       const char *userid,
                                                       const char *passwd,
                                                       const char *ha1,
                                                       const char *realm,
                                                       const char *domain,
                                                       const char *algorithm) {
	return AuthInfo::createCObject(username ? username : "", userid ? userid : "", passwd ? passwd : "", ha1 ? ha1 : "",
	                               realm ? realm : "", domain ? domain : "", algorithm ? algorithm : "");
}

LinphoneAuthInfo *linphone_auth_info_new_from_config_file(LpConfig *config, int pos) {
	char key[50];
	sprintf(key, "auth_info_%i", pos);
	if (linphone_config_has_section(config, key)) {
		LinphoneAuthInfo *ai = AuthInfo::createCObject(config, key);
		return ai;
	}
	return NULL;
}

void linphone_auth_info_write_config(LpConfig *config, LinphoneAuthInfo *obj, int pos) {
	// obj will be null when writing all auth infos to mark the end
	if (obj) {
		AuthInfo::toCpp(obj)->writeConfig(config, pos);
	} else {
		char key[50];
		sprintf(key, "auth_info_%i", pos);
		linphone_config_clean_section(config, key);
	}
}

LinphoneAuthInfo *linphone_auth_info_clone(const LinphoneAuthInfo *source) {
	if (source) {
		LinphoneAuthInfo *ai = AuthInfo::toCpp(source)->clone()->toC();
		return ai;
	}
	return NULL;
}

LinphoneAuthInfo *linphone_auth_info_ref(LinphoneAuthInfo *info) {
	if (info) {
		AuthInfo::toCpp(info)->ref();
		return info;
	}
	return NULL;
}

void linphone_auth_info_unref(LinphoneAuthInfo *info) {
	if (info) {
		AuthInfo::toCpp(info)->unref();
	}
}

void linphone_auth_info_set_password(LinphoneAuthInfo *info, const char *passwd) {
	AuthInfo::toCpp(info)->setPassword(L_C_TO_STRING(passwd));
}

void linphone_auth_info_set_passwd(LinphoneAuthInfo *info, const char *passwd) {
	linphone_auth_info_set_password(info, passwd);
}

void linphone_auth_info_set_username(LinphoneAuthInfo *info, const char *username) {
	AuthInfo::toCpp(info)->setUsername(L_C_TO_STRING(username));
}

void linphone_auth_info_set_algorithm(LinphoneAuthInfo *info, const char *algorithm) {
	AuthInfo::toCpp(info)->setAlgorithm(L_C_TO_STRING(algorithm));
}

void linphone_auth_info_set_available_algorithms(LinphoneAuthInfo *info, const bctbx_list_t *algorithms) {
	std::list<std::string> algoList;
	for (const bctbx_list_t *elem = algorithms; elem != NULL; elem = elem->next)
		algoList.push_back((const char *)elem->data);
	AuthInfo::toCpp(info)->setAvailableAlgorithms(algoList);
}

void linphone_auth_info_add_available_algorithm(LinphoneAuthInfo *info, const char *algorithm) {
	AuthInfo::toCpp(info)->addAvailableAlgorithm(L_C_TO_STRING(algorithm));
}

void linphone_auth_info_set_userid(LinphoneAuthInfo *info, const char *userid) {
	AuthInfo::toCpp(info)->setUserid(L_C_TO_STRING(userid));
}

void linphone_auth_info_set_realm(LinphoneAuthInfo *info, const char *realm) {
	AuthInfo::toCpp(info)->setRealm(L_C_TO_STRING(realm));
}

void linphone_auth_info_set_domain(LinphoneAuthInfo *info, const char *domain) {
	AuthInfo::toCpp(info)->setDomain(L_C_TO_STRING(domain));
}

void linphone_auth_info_set_ha1(LinphoneAuthInfo *info, const char *ha1) {
	AuthInfo::toCpp(info)->setHa1(L_C_TO_STRING(ha1));
}

void linphone_auth_info_set_tls_cert(LinphoneAuthInfo *info, const char *tls_cert) {
	AuthInfo::toCpp(info)->setTlsCert(L_C_TO_STRING(tls_cert));
}

void linphone_auth_info_set_tls_key(LinphoneAuthInfo *info, const char *tls_key) {
	AuthInfo::toCpp(info)->setTlsKey(L_C_TO_STRING(tls_key));
}

void linphone_auth_info_set_tls_cert_path(LinphoneAuthInfo *info, const char *tls_cert_path) {
	AuthInfo::toCpp(info)->setTlsCertPath(L_C_TO_STRING(tls_cert_path));
}

void linphone_auth_info_set_tls_key_path(LinphoneAuthInfo *info, const char *tls_key_path) {
	AuthInfo::toCpp(info)->setTlsKeyPath(L_C_TO_STRING(tls_key_path));
}

void linphone_auth_info_set_tls_key_password(LinphoneAuthInfo *info, const char *tls_key_password) {
	AuthInfo::toCpp(info)->setTlsKeyPassword(L_C_TO_STRING(tls_key_password));
}

void linphone_auth_info_clear_available_algorithms(LinphoneAuthInfo *info) {
	AuthInfo::toCpp(info)->clearAvailableAlgorithms();
}

const char *linphone_auth_info_get_username(const LinphoneAuthInfo *info) {
	const char *username = AuthInfo::toCpp(info)->getUsername().c_str();
	return strlen(username) != 0 ? username : NULL;
}

const char *linphone_auth_info_get_algorithm(const LinphoneAuthInfo *info) {
	const char *algo = AuthInfo::toCpp(info)->getAlgorithm().c_str();
	return strlen(algo) != 0 ? algo : NULL;
}

bctbx_list_t *linphone_auth_info_get_available_algorithms(const LinphoneAuthInfo *info) {
	std::list<std::string> algoList = AuthInfo::toCpp(info)->getAvailableAlgorithms();
	bctbx_list_t *result = NULL;
	for (auto i = algoList.begin(); i != algoList.end(); ++i)
		result = bctbx_list_append(result, ms_strdup(i->c_str()));
	return result;
}

const char *linphone_auth_info_get_passwd(const LinphoneAuthInfo *info) {
	return linphone_auth_info_get_password(info);
}

const char *linphone_auth_info_get_password(const LinphoneAuthInfo *info) {
	const char *passwd = AuthInfo::toCpp(info)->getPassword().c_str();
	return strlen(passwd) != 0 ? passwd : NULL;
}

const char *linphone_auth_info_get_userid(const LinphoneAuthInfo *info) {
	const char *userid = AuthInfo::toCpp(info)->getUserid().c_str();
	return strlen(userid) != 0 ? userid : NULL;
}

const char *linphone_auth_info_get_realm(const LinphoneAuthInfo *info) {
	const char *realm = AuthInfo::toCpp(info)->getRealm().c_str();
	return strlen(realm) != 0 ? realm : NULL;
}

const char *linphone_auth_info_get_domain(const LinphoneAuthInfo *info) {
	const char *domain = AuthInfo::toCpp(info)->getDomain().c_str();
	return strlen(domain) != 0 ? domain : NULL;
}

const char *linphone_auth_info_get_ha1(const LinphoneAuthInfo *info) {
	const char *ha1 = AuthInfo::toCpp(info)->getHa1().c_str();
	return strlen(ha1) != 0 ? ha1 : NULL;
}

const char *linphone_auth_info_get_tls_cert(const LinphoneAuthInfo *info) {
	const char *tlsCert = AuthInfo::toCpp(info)->getTlsCert().c_str();
	return strlen(tlsCert) != 0 ? tlsCert : NULL;
}

const char *linphone_auth_info_get_tls_key(const LinphoneAuthInfo *info) {
	const char *tlsKey = AuthInfo::toCpp(info)->getTlsKey().c_str();
	return strlen(tlsKey) != 0 ? tlsKey : NULL;
}

const char *linphone_auth_info_get_tls_cert_path(const LinphoneAuthInfo *info) {
	const char *tlsCertPath = AuthInfo::toCpp(info)->getTlsCertPath().c_str();
	return strlen(tlsCertPath) != 0 ? tlsCertPath : NULL;
}

const char *linphone_auth_info_get_tls_key_path(const LinphoneAuthInfo *info) {
	const char *tlsKeyPath = AuthInfo::toCpp(info)->getTlsKeyPath().c_str();
	return strlen(tlsKeyPath) != 0 ? tlsKeyPath : NULL;
}

bool_t linphone_auth_info_is_equal_but_algorithms(const LinphoneAuthInfo *auth_info_1,
                                                  const LinphoneAuthInfo *auth_info_2) {
	return auth_info_1 && AuthInfo::toCpp(auth_info_1)->isEqualButAlgorithms(AuthInfo::toCpp(auth_info_2));
}

const char *linphone_auth_info_get_tls_key_password(const LinphoneAuthInfo *info) {
	const char *tlsKeyPassword = AuthInfo::toCpp(info)->getTlsKeyPassword().c_str();
	return strlen(tlsKeyPassword) != 0 ? tlsKeyPassword : NULL;
}

const LinphoneBearerToken *linphone_auth_info_get_access_token(const LinphoneAuthInfo *auth_info) {
	return toC(AuthInfo::toCpp(auth_info)->getAccessToken());
}

const LinphoneBearerToken *linphone_auth_info_get_refresh_token(const LinphoneAuthInfo *auth_info) {
	return toC(AuthInfo::toCpp(auth_info)->getRefreshToken());
}

void linphone_auth_info_set_access_token(LinphoneAuthInfo *auth_info, LinphoneBearerToken *token) {
	AuthInfo::toCpp(auth_info)->setAccessToken(bellesip::getSharedPtr<BearerToken>(token));
}

void linphone_auth_info_set_refresh_token(LinphoneAuthInfo *auth_info, LinphoneBearerToken *token) {
	AuthInfo::toCpp(auth_info)->setRefreshToken(bellesip::getSharedPtr<BearerToken>(token));
}

void linphone_auth_info_set_authorization_server(LinphoneAuthInfo *auth_info, const char *uri) {
	AuthInfo::toCpp(auth_info)->setAuthorizationServer(L_C_TO_STRING(uri));
}

const char *linphone_auth_info_get_authorization_server(const LinphoneAuthInfo *auth_info) {
	return L_STRING_TO_C(AuthInfo::toCpp(auth_info)->getAuthorizationServer());
}

const char *linphone_auth_info_get_token_endpoint_uri(const LinphoneAuthInfo *auth_info) {
	return L_STRING_TO_C(AuthInfo::toCpp(auth_info)->getTokenEndpointUri());
}

void linphone_auth_info_set_token_endpoint_uri(LinphoneAuthInfo *auth_info, const char *uri) {
	AuthInfo::toCpp(auth_info)->setTokenEndpointUri(L_C_TO_STRING(uri));
}

const char *linphone_auth_info_get_client_id(const LinphoneAuthInfo *auth_info) {
	return L_STRING_TO_C(AuthInfo::toCpp(auth_info)->getClientId());
}

void linphone_auth_info_set_client_id(LinphoneAuthInfo *auth_info, const char *client_id) {
	AuthInfo::toCpp(auth_info)->setClientId(L_STRING_TO_C(client_id));
}

time_t linphone_auth_info_get_expires(const LinphoneAuthInfo *auth_info) {
	return AuthInfo::toCpp(auth_info)->getExpires();
}

void linphone_auth_info_set_expires(LinphoneAuthInfo *auth_info, time_t expires) {
	AuthInfo::toCpp(auth_info)->setExpires(expires);
}
